using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using GoChat_for_Windows.Models;
using Newtonsoft.Json.Converters;

namespace GoChat_for_Windows.Services
{
    public class UdpService : IDisposable
    {
        private readonly UdpClient _udpClient;
        private readonly string _serverIp = "121.199.21.194";
        private readonly int _serverPort = 10000;
        private CancellationTokenSource? _heartbeatCancellation;
        private bool _isConnected;
        private const int MAX_RETRIES = 3;
        private const int RETRY_DELAY_MS = 1000;

        public event EventHandler<Message>? MessageReceived;
        public event EventHandler<bool>? ConnectionStatusChanged;

        private readonly JsonSerializerSettings _jsonSettings;

        public UdpService()
        {
            _udpClient = new UdpClient();
            _jsonSettings = new JsonSerializerSettings
            {
                DateTimeZoneHandling = DateTimeZoneHandling.Utc,
                DateFormatString = "yyyy-MM-ddTHH:mm:ss.fffZ",
                Converters = { new StringEnumConverter() }
            };
        }

        public async Task StartAsync(User currentUser)
        {
            try
            {
                _udpClient.Connect(_serverIp, _serverPort);
                _isConnected = true;
                ConnectionStatusChanged?.Invoke(this, true);

                // 启动心跳
                StartHeartbeat(currentUser);

                // 启动消息接收
                _ = Task.Run(async () =>
                {
                    while (_isConnected)
                    {
                        try
                        {
                            var result = await _udpClient.ReceiveAsync();
                            var json = Encoding.UTF8.GetString(result.Buffer);
                            var message = JsonConvert.DeserializeObject<Message>(json, _jsonSettings);
                            
                            if (message != null)
                            {
                                if (message.MessageType == MessageType.HeartbeatAck)
                                {
                                    // 心跳回执,不需要处理
                                    continue;
                                }
                                
                                MessageReceived?.Invoke(this, message);
                            }
                        }
                        catch (Exception)
                        {
                            // 接收消息出错,继续尝试
                            await Task.Delay(100);
                        }
                    }
                });

                // 发送初始心跳消息
                var initialHeartbeat = new Message
                {
                    SenderId = currentUser.Id,
                    MessageType = MessageType.Heartbeat,
                    SendTime = DateTime.UtcNow
                };
                await SendMessageAsync(initialHeartbeat);
            }
            catch (Exception)
            {
                _isConnected = false;
                ConnectionStatusChanged?.Invoke(this, false);
                throw;
            }
        }

        public async Task<bool> SendMessageAsync(Message message)
        {
            if (!_isConnected) return false;

            int retryCount = 0;
            while (retryCount < MAX_RETRIES)
            {
                try
                {
                    // 确保时间戳是UTC时间
                    message.SendTime = DateTime.UtcNow;
                    
                    var json = JsonConvert.SerializeObject(message, _jsonSettings);
                    Console.WriteLine($"发送消息: {json}"); // 添加日志
                    var bytes = Encoding.UTF8.GetBytes(json);
                    await _udpClient.SendAsync(bytes, bytes.Length);
                    return true;
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"发送消息失败: {ex.Message}"); // 添加错误日志
                    retryCount++;
                    if (retryCount < MAX_RETRIES)
                    {
                        await Task.Delay(RETRY_DELAY_MS);
                    }
                }
            }
            return false;
        }

        private void StartHeartbeat(User currentUser)
        {
            StopHeartbeat();
            _heartbeatCancellation = new CancellationTokenSource();

            _ = Task.Run(async () =>
            {
                while (!_heartbeatCancellation.Token.IsCancellationRequested && _isConnected)
                {
                    try
                    {
                        await Task.Delay(30000, _heartbeatCancellation.Token); // 30秒发送一次心跳

                        var heartbeat = new Message
                        {
                            SenderId = currentUser.Id,
                            MessageType = MessageType.Heartbeat,
                            SendTime = DateTime.UtcNow
                        };

                        await SendMessageAsync(heartbeat);
                    }
                    catch (TaskCanceledException)
                    {
                        // 正常取消
                        break;
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"发送心跳失败: {ex.Message}"); // 添加错误日志
                        // 心跳发送失败,继续尝试
                        await Task.Delay(1000);
                    }
                }
            }, _heartbeatCancellation.Token);
        }

        private void StopHeartbeat()
        {
            if (_heartbeatCancellation != null)
            {
                _heartbeatCancellation.Cancel();
                _heartbeatCancellation.Dispose();
                _heartbeatCancellation = null;
            }
        }

        public void Stop()
        {
            _isConnected = false;
            StopHeartbeat();
            ConnectionStatusChanged?.Invoke(this, false);
        }

        public void Dispose()
        {
            Stop();
            _udpClient.Dispose();
        }
    }
} 